﻿using InCom.OTM.Adapters;
using InCom.SyncStatus;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace InCom.Core.SyncInteractive
{
    // using InCom.API.Protocols;
    using InCom.Utilities.Protocol;
    using InCom.API.Protocols.Entitys;
    using inCom.Logs;
    using InCom.API.Protocols;
    using InCom.Utilities;
    /// <summary>
    /// 数据同步与incom交互主要处理功能
    /// </summary>
    public class SyncDataInteractiveSupervise
    {
        #region 构造函数与单例


        /// <summary>
        /// 外部不能直接实例化
        /// </summary>
        protected SyncDataInteractiveSupervise()
        {

        }

        private static readonly SyncDataInteractiveSupervise instance = new SyncDataInteractiveSupervise();
        /// <summary>
        /// 数据同步与incom交互主要处理功能,静态访问单例
        /// </summary>
        public static SyncDataInteractiveSupervise Instance
        {
            get { return instance; }
        }



        #endregion

        #region 实时数据

        /// <summary>
        /// 实时数据转发字典,key,unit终端号, SyncPoint需要发送到的 数据同步节点
        /// </summary>
        private Dictionary<uint, Dictionary<string, SyncPoint>> _realDataTransmissionDictionary = new Dictionary<uint, Dictionary<string, SyncPoint>>(2000);
        /// <summary>
        /// 实时数据转发字典,key,unit终端号, SyncPoint需要发送到的 数据同步节点
        /// </summary>
        public Dictionary<uint, Dictionary<string, SyncPoint>> RealDataTransmissionDictionary
        {
            get { return _realDataTransmissionDictionary; }
        }

        #endregion

        /// <summary>
        /// 终端注册时引发的委托
        /// </summary>
        public Action<SyncPoint> OnTerminalRegistAction;


 

   

        /// <summary>
        /// incom 数据同步 协义处理主接口
        /// 约定:
        /// 非终端交互指令需要把userflg 发送回来
        /// 这里表示接收到incom.api 或者其它incom发送过来的信息
        /// </summary>
        /// <param name="protocol">协义数据体</param>
        public void ProtocolProcess(InCom.Utilities.Protocol.BaseTcpProtocolEntity protocol, SyncPoint syncPoint)
        {
           



            

            //终端注册指令不进行打印
            if (protocol.MSGSEQ != (ushort)APIProtocolType.TERMINAL_REGISTRATION
                &&
                //终端上下线信息不打印
                protocol.MSGSEQ!=(ushort)APIProtocolType.TERMINALONOFFLINE_RES
                )
            {
                inCom.Logs.LogProvider.Create().Write(inCom.Logs.EventType.Information, string.Format("接收到Sync消息ID,{0},名称:{1},消息来源:{2},{3}", protocol.MSGSEQ.ToString("d5"), Enum.GetName(typeof(APIProtocolType), protocol.MSGSEQ), syncPoint.TagName, Newtonsoft.Json.JsonConvert.SerializeObject(protocol)));
            }

            try
            {
                //各协议的处理逻辑
                switch (protocol.MSGSEQ)
                {
                    //充电控制转入终端处理
                    case 0xF1:
                    case 0xF3:
                    case 0x0780:
                        //wuwei 20151119 添加虚拟CAN分支
                    case 0x0101:
                        //wuwei 20151123 添加自动VIN分支
                    case 0x0201:
                    case 0x0808:
                        //wuwei 20160109 添加CAN2分支
                    case 0x4101:
                        //wuwei 20160217 添加命令串透传分支
                    case 0x0A30:
                       // ProtocolLogicAdapter.Instance.DoRequest(protocol, syncPoint);
                        break;




                    //处理incom.api 发送过来的终端注册指令
                    case (ushort)APIProtocolType.TERMINAL_REGISTRATION:
                        TerminalRegist(protocol, syncPoint);
                        break;
                    case (ushort)APIProtocolType.TERMINAL_CANCELED:
                        //incom.api发过来的终端注销指令,不再提供实时数据转发
                        TerminalRegist(protocol, syncPoint, false);
                        break;
                    case (ushort)APIProtocolType.TERMINALONOFFLINE_RES:
                        //终端上下线消息回应
                        break;
                    case (ushort)APIProtocolType.TERMINAL_ONLINE_STATUS:
                        //接收所有在线终端列表处理
                        //  TerminalOnlinesQuery(protocol, syncPoint);
#if 命令下发调试
                        Console.WriteLine("接收所有在线终端列表处理 方法 ,flg:{0}" + "指令", protocol.UserFlag);
#endif
                        break;
                    default:
                        //处理与incom.api 终端交互指令,比如 参数设置,查询,控制指令等,需要翻译的指令
#if 命令下发调试
                        Console.WriteLine("转入TerminalInteractive(protocol, syncPoint);方法 ,flg:{0}" + "指令", protocol.UserFlag);
#endif
                        TerminalInteractive(protocol, syncPoint);
                        break;
                }
            }
            catch (Exception ex)
            {
                inCom.Logs.LogProvider.Create().Write(EventType.Information, string.Format("处理交互协议时出现问题 方法:SyncDataInteractive.ProtocolProcess.消息ID:{0},{1}", protocol.MSGSEQ, ex));
            }
        }

        /// <summary>
        /// 将指令协议发送到指令的incom,api节点中
        /// </summary>
        /// <param name="apipProtocol">指令内部交互协议</param>
        /// <param name="syncPoint"></param>
        public void Send(InCom.Utilities.Protocol.BaseTcpProtocolEntity apipProtocol, SyncPoint syncPoint)
        {
            SyncDataInteractiveSendBuffer.Instance.Push(apipProtocol, syncPoint);
        }

        #region 各种incom数据同步交互指令处理
        /// <summary>
        /// 终端注册指令处理
        /// </summary>
        /// <param name="protocol">协议数据对像</param>
        /// <param name="syncPoint">数据同步节点</param>
        /// <param name="isRegist">默认是处理注册的事件,false表示注销事件,需要删除</param>
        protected void TerminalRegist(BaseTcpProtocolEntity protocol, SyncPoint syncPoint, bool isRegist = true)
        {
            //转换协议类型
            TerminalRegistrationEntity regsit = protocol as TerminalRegistrationEntity;
            if (regsit == null)
            {
                return;
            }


            //1.查看当前需要注册的终端号是否包括在需要发送的实时数据集合字典中

            //2.不包含则将当前数据同步节点与终端号添加到集合中,如果是注销事件则删除

            //3.如果结果已经存在集合,则添加节点,如果是注销事件则删除

            if (regsit.Terminal != null)
            {
                //这个锁是不是有点大?
                lock (_realDataTransmissionDictionary)
                {
                    foreach (var item in regsit.Terminal)
                    {
                        //数据同步节点集合
                        Dictionary<string, SyncPoint> listSynPoint = null;
                        _realDataTransmissionDictionary.TryGetValue(item, out listSynPoint);
                        //注册事件
                        if (listSynPoint == null)
                        {
                            //注册事件
                            if (isRegist)
                            {
                                listSynPoint = new Dictionary<string, SyncPoint>(3);
                                listSynPoint.Add(syncPoint.TagName, syncPoint);
                                //添加到队列集合中
                                _realDataTransmissionDictionary.Add(item, listSynPoint);
                            }
                        }
                        else
                        {
                            //注册事件
                            if (isRegist)
                            {
                                //如果,当前数据同步节点不包含在需要发送的节点中则再次添加
                                if (!listSynPoint.ContainsKey(syncPoint.TagName))
                                {
                                    listSynPoint.Add(syncPoint.TagName, syncPoint);
                                }
                                else
                                {
                                    //如果已经存在则更新值
                                    listSynPoint[syncPoint.TagName] = syncPoint;
                                }
                            }
                            else
                            {
                                //注销事件 删除数据
                                listSynPoint.Remove(syncPoint.TagName);
                                //如果全部数据为空则进行数据删除,
                                // 这里想了一下,还是不进行删除了,删除后如果再注册又需要重新创建对像了
                                //if(listSynPoint.Count==0)
                                //{
                                //    _realDataTransmissionDictionary.Remove(item);
                                //}
                            }

                        }


                    }

                }
            }
            //注册终端实时数据时引发的动作
            if (OnTerminalRegistAction != null && isRegist)
            {
                OnTerminalRegistAction(syncPoint);
            }

        }

        /// <summary>
        /// 终端交互指令处理
        /// </summary>
        /// <param name="protocol">协议数据对像</param>
        /// <param name="syncPoint">数据同步节点</param>
        protected void TerminalInteractive(BaseTcpProtocolEntity protocol, SyncPoint syncPoint)
        {
            //看看当前协议是不是与终端交互的协议
            if (PluginModulesManager.Instance.GetTerminalInteractive(protocol.MSGSEQ) != null)
            {
                ITerminalInteractive iterm = protocol as ITerminalInteractive;

                return;
                //步骤1,查找终端对像
                TerminalEntity terminalEntity = null;// ProtocolLogicAdapter.Instance.OnlineTerminalManager.Find(iterm.TerminalCode);
                if (terminalEntity == null)
                {

#if 命令下发调试
                    Console.WriteLine("转到 终端不在线:{0}", iterm.TerminalCode);
#endif
                    //发送不在线回应
                    Send(new TerminalNotOnLine()
                             {
                                 SendTime = DateTime.Now,
                                 SEQ = protocol.SEQ,
                                 SrcMSGSEQ = protocol.MSGSEQ,
                                 UserFlag = protocol.UserFlag,
                                 TerminalCode = iterm.TerminalCode
                             }, syncPoint);

                    inCom.Logs.LogProvider.Create().Write(EventType.Information, string.Format("终端:{0}不在线,API终端交互,下发指令MSGSEQ:{1}不做处理", iterm.TerminalCode, protocol.MSGSEQ));
                    return;
                }





                switch (protocol.MSGSEQ)
                {
                    #region 终端参数查询
                    //终端参数查询,需要分成两条指令处理,固件版本需要分成两条指令处理
                    case (ushort)APIProtocolType.TERMINAL_PARAMETER_QUERY:
                        //终端号值
                        TerminalParameterQuery apiProtocol = (TerminalParameterQuery)protocol;
#if 命令下发调试
                        Console.WriteLine("转到 终端参数查询");
#endif
                        //转到对应的处理方法
                        Process(apiProtocol, terminalEntity, syncPoint);
                        break;
                    #endregion

                    #region 参数设置
                    case (ushort)APIProtocolType.TERMINAL_PARAMETER_SETTING:
#if 命令下发调试
                        Console.WriteLine("转到 参数设置");
#endif
                        //转到对应的处理方法
                        ProcessCommon((TerminalParameterSetting)protocol, terminalEntity, syncPoint);


                        break;
                    #endregion

                    default:
#if 命令下发调试
                        Console.WriteLine("转到ProcessCommon(protocol, terminalEntity, syncPoint);");
#endif
                        //转到对应的处理方法
                        ProcessCommon(protocol, terminalEntity, syncPoint);

                        break;
                }

            }
        }



        #endregion

        #region 各种与终端交互协议的协议处理入口方法

        /// <summary>
        /// 进行终端参数查询处理
        /// </summary>
        /// <param name="apiProtocol"></param>
        protected virtual void Process(TerminalParameterQuery apiProtocol, TerminalEntity terminalEntity, SyncPoint syncpoint)
        {

#if 命令下发调试
            //     Console.WriteLine("添加发送指令队列: {0},终端:{1}", query.Afn.ToString("X2"), query.TerminalCode);
#endif
            //发送参数查询
            //  TerminalSend.TerminalSendBuffer.Instance.Push(query, terminalEntity, terminalEntity.RemoteIpEP);



        }

        /// <summary>
        /// 进行终端参数设置处理
        /// </summary>
        /// <param name="apiProtocol"></param>
        protected virtual void ProcessCommon(BaseTcpProtocolEntity apiProtocol, TerminalEntity terminalEntity, SyncPoint syncpoint)
        {

            //添加到终端指令集合
            //TerminalCmmmandManager.Instance.AddCommand(query.TerminalCode, new CommandEntity()
            //                                                                  {
            //                                                                      ClientSEQ = apiProtocol.SEQ,
            //                                                                      SEQ = query.Seq,
            //                                                                      ClientSessionID = apiProtocol.UserFlag,
            //                                                                      TerminalCode = terinteractive.TerminalCode,
            //                                                                      ProtocolEntity = query,
            //                                                                      ClientProtocolEntity = apiProtocol,
            //                                                                      SyncPoint = syncpoint,
            //                                                                      LastSendTime = DateTime.Now,
            //                                                                  });
            //发送指令到终端
            //TerminalSend.TerminalSendBuffer.Instance.Push(query, terminalEntity, terminalEntity.RemoteIpEP);



        }

        #endregion
    }
}
